/**
 * 无数据域双向链表
 * 节点结构仅包含指向前一个节点和后一个节点的指针。
 * 而实现无数据域链表，如何去访问链表元素内容则需要使用一个最为关键的宏offsetof。
 * offsetof 是 C 标准库中的一个宏，用于计算结构体中成员的偏移量。它的定义在头文件 stddef.h 中，使用时需要包含该头文件。
 * offsetof 宏接受两个参数：结构体类型和成员名，返回成员在结构体中的偏移量（以字节为单位）。
 * #define offsetof(type, member) ((size_t)&(((type *)0)->member))
 * 使用 offsetof 可以方便地获取结构体中成员的偏移量，这在一些底层编程和数据结构实现中非常有用。
 * */

#include <stdio.h>
#include <stddef.h>     /*包含offsetof宏*/
/*定义节点结构体*/
struct Node
{
    struct Node *prev;
    struct Node *next;
};

/*定义测试结构体*/
struct Data
{
    /* data */
    int data;
    struct Node list;
};

/*插入节点到链表尾部*/
void insert(struct Node *head, struct Node *newNode)
{
    struct Node *current = head;
    while(current->next != NULL)
    {
        current = current->next;
    }

    newNode->prev = current;
    newNode->next = NULL;
    current->next = newNode;
}

/*打印链表内容*/
void printList(struct Node *head)
{
    printf("List:");
    struct Node *current = head->next;

    while (current != NULL)
    {
        /*通过偏移量找到struct data类型变量的首地址，从而可以获取到data结构体中的其他数据*/
        struct Data *test = (struct Data *)((char *)current - offsetof(struct Data, list));
        printf("%d", test->data);

        current = current->next;
        if(current)
        {
            printf(" -> ");
        }
    }
    printf("\n");
    
}

int main(int argc, char **argv)
{
    /*创建虚拟链表节点头，不标识实际的数据*/
    struct Node head;
    head.next = NULL;
    head.prev = NULL;

    /*创建并插入节点*/
    struct Data test1 = {1, {NULL, NULL}};
    struct Data test2 = {2, {NULL, NULL}};
    struct Data test3 = {3, {NULL, NULL}};

    /*插入链表节点*/
    insert(&head, &test1.list);
    insert(&head, &test2.list);
    insert(&head, &test3.list);

    /*打印链表*/
    printList(&head);
    
    printf("\n");
    printf("%ld %ld \n", sizeof(struct Node), sizeof(struct Data));
    printf("%ld %ld\n", sizeof(int), sizeof(int *));

    return 0;

}



